{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Large-scale QAOA via Divide-and-Conquer\n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overview\n",
    "\n",
    "[Quantum Approximation Optimization Algorithm](./QAOA_EN.ipynb) (QAOA) is a promising hybrid quantum-classical algorithm to solve combinatorial optimization problems approximately. However, its applicability is restricted by the qubit limitation for large-scale problems and its execution time scales exponentially with the problem size. Detailed and other limitations can be found in [1].\n",
    "\n",
    "Divide-and-Conquer (DC) is a largely used technique to address similar challenges as those listed above, such as quicksort and fast Fourier transform (FFT). It recursively breaks down a problem into several subproblems of the same type until these subproblems can be solved directly.  \n",
    "\n",
    "DC-QAOA proposed by Junde Li et al. in 2021 [2] applied such technique on QAOA to solve the Max-Cut problem. The methodology presented below adopts this DC-QAOA scheme with some modifications."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Methodology"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Large Graph Partitioning (LGP)\n",
    "\n",
    "Let $G(V,E)$ be an undirected graph with $n$ vertices and $k$ be the qubit (vertex) limit, i.e. available qubit size in NISQ computers. LGP partitions $G$ into exactly two subgraphs $G_0$ and $G_1$, and at least one node is shared between these two subgraphs so that no edges of $G$ are missed. Those shared nodes that enables this separation are separation nodes. Note that number of separation nodes should be smaller than the max qubit limit. \n",
    "\n",
    "The following code shown is to define such partition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:51:46.909218Z",
     "start_time": "2021-05-11T06:51:45.642375Z"
    }
   },
   "outputs": [],
   "source": [
    "import networkx as nx # version of networkx >= 2.5\n",
    "import matplotlib.pyplot as plt\n",
    "from itertools import combinations\n",
    "\n",
    "# Partition a graph into two subgraphs\n",
    "def NaiveLGP(g, k):\n",
    "    E = list(g.edges)\n",
    "    E = [(min([u, v]),max([u, v])) for (u, v) in E]\n",
    "    E.sort(key = lambda tup:tup[0])\n",
    "    V = list(g.nodes)\n",
    "    V.sort()\n",
    "\n",
    "    counter = 1\n",
    "    while counter < k:\n",
    "        num_nodes = counter\n",
    "        nodes_combo = list(combinations(V, num_nodes))\n",
    "        # Check suitable separation path\n",
    "        for p in nodes_combo:\n",
    "            V1 = [x for x in V if x not in p]\n",
    "            E1 = [e for e in g.edges if e not in g.edges(p)]\n",
    "            G1 = nx.Graph()\n",
    "            G1.add_nodes_from(V1)\n",
    "            G1.add_edges_from(E1)\n",
    "            S = [G1.subgraph(c).copy() for c in nx.connected_components(G1)]\n",
    "            if len(S) == 2:\n",
    "                # Add the seperate paths to two subgraphs\n",
    "                V_S0 = list(S[0].nodes)\n",
    "                E_S0 = list(S[0].edges)   \n",
    "                V_S1 = list(S[1].nodes)\n",
    "                E_S1 = list(S[1].edges)\n",
    "                for (u,v) in g.edges(p):\n",
    "                    if u in V_S0 or v in V_S0:\n",
    "                        S[0].add_edges_from([(u,v)])\n",
    "                    if u in V_S1 or v in V_S1:\n",
    "                        S[1].add_edges_from([(u,v)])\n",
    "                    if u in p and v in p:\n",
    "                        S[0].add_edges_from([(u,v)])\n",
    "                        S[1].add_edges_from([(u,v)])\n",
    "\n",
    "                return S\n",
    "\n",
    "        counter += 1\n",
    "    print(\"G has connectivity above k\")\n",
    "\n",
    "    return {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One example for illustration is given below. The graph is a random with $10$ vertices and the qubit (vertex) limit is $9$ vertices. Then red vertices are those selected to be removed so that the rest is disconnected and can be partitioned. We then add separation nodes with incident edges back to these two subgraphs to avoid missing information of the graph. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:51:47.579620Z",
     "start_time": "2021-05-11T06:51:46.912332Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1MAAADnCAYAAAD7CwxiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Z1A+gAAAACXBIWXMAAAsTAAALEwEAmpwYAABJFklEQVR4nO3debzc8/XH8dc7+yKJfS+x7wSt2tdYf7ZaSqKEUiWWCkW1SpVWKU0qYpdYY09RlBIttRWlqCX2NYgt673Zz++Pz0SSe2du7p3M3O/M3Pfz8biPxJ3vfJ3LnZnP+SznKCIwMzMzMzOzlmmXdQBmZmZmZmbVyMmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFaFD1gHYXBLtgd2AHwErkP7/fAH8FbglgikZhrdwpLWBnwLrAz2AicALwJVEvJdlaGYtJi0KDAB2ARYHpgEfACOAx4iI7IIzM7NKUdNjOwNA/szPnkRX4KTcVzdgkQaXTCatIl4P/C6CT1ozvoUi7Qn8GtgQaA90nOfR6cBs4BngHCL+2erxmbWEtAZwFnAAMAvoPs+jAUwBvgEuBK4gYmarx2hmZpmr6bGdzcfJVMYklgRGA2sAXRdw+QxgErBzBC+UO7aFIgn4A3A86U1kQeqAs4i4uKxxmRVL2gG4l/Q6bb+Aq+uAZ4G9iJhc7tDMzKxy1OzYzvJyMpUhiUWA54DVmH/FpilBms3YLII3yhXbQpPOB05g/pn7BakDziDikvIEZVYkaQvgEZo3MTDHVOA/wA5EzChLXGZmVlFqemxneTmZypDESOAHQJcWPnU28AmwSgSzSh7YwpJ2Be6iZYnUHHXAdkQ8X9qgzIokdQc+BhYt4tl1wFAiflHSmMzMrCLV7NjOCnI1v4xILE2BF9uNN8LYsTBhAowZA0ce2ejp7UgDu13LHWeRziRfItWpE1xzDbz/PkycCC++CLvt1vCqLsCp5Q/RrNn6UahYz2KLwahRMHly+r3u16/hFd2AgUgt/VA1M7MqI7EUBcZ2//gH1NfDpEnp643G60+VPrazApxMZeco0rJuI+efD717Q69esPfecN55sMkmjS7rAZxW3hCLIK0GbJr3sQ4d4KOPYLvt0g935plw++2w8srzXtUO2BtpiVaI1qxp6ezfL2h8cDgZNgymT4dlloFDDoHLL4d118135YFljNLMzCpDwbEdwPHHQ48e6WvttfNeUpljO2uSk6nsHE+BQ4mvvZbGZwAR6Wu11fLe4/sSy5crwCL9hEKz+HV1cM458MEH6Ye6/3547z3YtFHuFcAhZY7TrDn6AMvmfaRbN9h/f/j1r2HKFHjySbj3Xjj00IZX9gAGlTdMMzOrACew4IITC1KJYztrgpOpDEgIWKapa4YNS+OzMWPg00/hgQfyXjYNWKkMIS6MdWnugcull4Y114RXX234SFdgzRLHZVaMVaHA3vU114SZM+Gtt+Z+76WXYL318l1daa9TMzMroeaM7c4/H774Ap54Im3SKaASx3bWBDftzUanBV1w3HFwwgmwxRaw/fYwbVq+q8b3gv2flh4teYDFehTYoTkXdugAN98M11+fMsbGepU0MLPidKfQpNMii6Szf/OaMCHt32jMZ6bMzACJLsBWwJKAgK+BpyOYlGlgC6/Jsd3pp8/deXTwwfDXv0KfPvDuu3kvL6aAl2XEK1PZmE4Te2rnmD077RxacUU49th8Vyw6AUZvFhGqlK8d4O4F/vRSqrIxfXraQJzfVwu8j1n5TaTQytTkydCz5/zf69kznSxurK7UgZmZVROJVSUGA18Ao4Crcl+3A59LXC2Rd2m/EknqKGlNSXtLOhXaDYNZBcfVzz6bPjamT4cbbkjjuz32KHj7iQUfsYrjlakMRBAS75N6ECxQhw4Fz0x1BvLPaWTnOVIlmsJ7hq+9Nh3Y32OPtE2qscnAy+UJz6xFXqPQbOObb6YX5+qrw9tvp+9ttFG+basAr5crQDOzSpbb/nYecDJpEr/QCs7hwCEStwA/jSDvAKG1SVoSWGuer7Vzf/YmlTIfk77ieZi6G3RfoTn3jUhzy3lU4tjOmuCVqexcBExp+M2lloKDDoLu3aFdO9hll1RtefToRs+fDfwtouJWcIaTlu3zu/xyWGcd2GsvmDq10FXtgNvKEJtZy0S8CeTNjqirS2XRf/vbVIxiyy1hn33Squu8l8Gsa2C0VOBj08ysRuUSqauBn5G2Oze1Fa4DaSL2YOBeifbljzDJrTKtLWkfSadJGi7pSUlfAm8DfwK2ByYANwAHAItGxGoRsUdEDIqIK6D7ueQZ2/XqlcZznTtD+/bQvz9suy08+GDDK2cHzHioAsd21gQ37c1I6pA9+wtoN99ZiiWXhDvvTBPc7dqlwneXXJLaMzUwBdglgqdaK+Zmk+4B9qJhUrXSSukHmjp1/hWpn/4URo4EYBbMElzdLiLvxkazVicdQJokaHwYarHFYPhw2Hln+Oor+MUv4JZb5rukHib3gPdmQXtgMHBzRNS3RuhmZlmSOA04i5afAaoDhkdwQulikUjntBquMK0FrExqzj4GeINvV5t4AxgXzRwsp7Ed42iwO2fJJVMhsbXXhlmzUo+pX/8aHnmk4R3qZ8Fu38Dj5wJXRUTBWWerHE6mMpB7QR8Kf74cjukInZpX/W6uGcD/gE0jFnz2qtVJ3wMeo4jyoPUw+/vw/CvQLyK8zG3ZkzoC7wAr0PLV/CnALwVDgR1JJdK/B1wJXBYRn5UyVDOzSiHRjZRY5E2kDjoIzj47zbN+9hkcfniqcjePqcAqEbTofVJSJ9IxinmTpTnJk5g/WZqTML0TEXlLfbWUxEXAsaSm7S2RG9t1/AnMPBvYBPgDcI2TqsrmZKqVSVqWdOByZVjix/DlBcCWND/xmEk6vNkngnFlCnPhST8mDSBb8mZSPw36dYE1SI1SzwSubO6MkFnZpGbUzwM9aX5CVQf8BTiUeX6HJa1F2vJyMHAvMDgiXiptwGZm2ZL4MfBn8jQ979s37bg56KBUmGG55dL3x46d77KpwPkR/LbxvSVgKeZPmOb8/TvAh8yfLM35+xflHlNIdAAeZCHHdpI2BX4DbAycD1zrpKoyOZlqJbkX/kGkN5argd9GxHSJzsCtQF/yvOE0UEc67Lh9BGMXcG32pMOAy0l7pJsqdjKdNCNzMBH3padqXeA6YDxwZER8VNZYzRYkJUH/JCVUTU0SBOm1eiNwPBF5qwFKWhw4mtTA+03SFsD7I2J2CaM2M8uExBgK9Ix88slUi2r48AXdJb6GZXeAcavTeGvebPInTO9ExPTS/BTFKeXYTtJ3SUnVRsxNqkqyimal4WSqFUhaipRUrAsMiIjn5n+cdsCewGmkZd32zD2kOZv0QhsHXAjcGFFFZZaldUgVfA4hlZie901lEmnJ/RrgEiLem/+p6kD6bzIIOB0Y4VUqy5S0KHAkcArpd3kR5p4NnEZKpB4DLiSiWQ3glLYRHkj6Pe9FmnC5LiIaHWI2M6sGuWSijjwr+e3aQX09nHUWHHUUdOkCd98Np56ary7VFGDj9+CtV2iwNS8ivizvT7FwSj22k7QZcDawIfB7YLiTqsrgZKrMJO0HDCPNUp+1oCVaidWB/YDlSC+6z0m9cJ+syPNRzSX1IA0Y1wAWI/WReg0YxQIO40vaELgeGAv8JCIqf1XOapvUjjTjuCWwNHNnFu8g4uPibimRGlmeDGwLXAtc6lVZM6s2EssA75Fnm9tyy6XtfM8/nwr7zpgB99wD//wnnHlmw6tjImj7CF4sf9TlU8qxnaTvk5Kq9ZmbVGW6EtfWOZkqk9wWnqGkw+aHR0TlVd2rIrkDpb8kHeo8GRjpVSqrVZJWBU4EDgMeIp2rejbbqMzMmkdiMeAz8pRCX3RR+OYbGDAgNa8F2G+/lEhtskmjW00Ctogo0KKiDZO0OSmpWpeUVI1wUpUN95kqA0l7Aq/w7WFCJ1ILKyKmR8RvgN2BM4C7JC2TbVRm5RER70bEScAqpEbYt+d6nhyQ2/5qZlbJJlCg5+T48fDRR6lp7RxNTI3OWcWxBiLimYjYnVTM6AfAm5KOzk0+WytyMlVCknpJGgFcAvSPiJMionrON1WBiHgB2JS0Z/olSQdmHJJZ2UTEhIj4E7A6qUDFIOAtSSdL6pVtdGZm+UUwm1TNNG9BnREj4IQTYKml0krVoEFw3315b/WfCCr6bFTWIuLpiNgN6A/sT0qqfpI7j2utwMlUiUjahbQaVQ9sGBGPZRxSzYqIaRFxBrAvcK6kWyUtmXFYZmUTETMj4s6I2IpUFfR7wLuSBktaJePwzMzyuZg0Jmrk3HPhuefgzTfh9dfhxRfhd79rdNkkUnEGa4aIeCoidiUV/PohKak60klV+fnM1EJSKqxwEbAbqYR3o37WVj6SugLnAf2AYyPinoxDMmsVkr5DKqt+JKmC4GDgSZ8lNLNKICFSoam1KLDlbwG+AJaPYGZJA2sjJG1NKqm+KmmcdGNEzMg0qBrllamFIGkH4GVSD6UNnUi1voioj4hTSLP1F0u6QdJiWcdlVm4R8VFEnA70JlWFGgE8K6m/ZyLNLGu5KnUHwKxiGs3WAfs5kSpeRDwREX2BAaTVqjckHeHPh9JzMlUESd0lDSWVOz8uIo6MiAlZx9WWRcS/SA3tJgCvSNo945DMWkVETI6IYaTZ33OBnwDvSfpFrqqomVlG1Al2nAoz6ilwfiqPOuCgCJ4oY2BtRkT8KyJ2Ao4ADgVel3S4ixmVjpOpFpK0FfBfYFFgg4h4INOA7FsRMSUiTiCVk75c0jWSemYdl1lriIjZEXFvROxAahS5DvCOpMskrZlxeGbWxkhaD3gAHv8JdNwYeByYCuQr3z2TdL7qOWC7CPKXo7CiRcTjEbEjaWv44aSVqgFOqhaez0w1U+5szrmkaikDI+LubCOypuSSqD8Cu5LOso3OOCSzVidpOWAg8FPgWdK5qkd9rsrMyik3gfMP4NSIGDn3+/QmnfU8GOhFOks1EfgrMCSC11s/2rZJ0vbAOcDypPHtyIho9rbKXC+xI4D/AxYDZgAfA8OBByOYVeKQK5aTqWbIdZu+jnQ+6riIcJnOKiFpV+Aa0hv1aRExOeOQzFpdbjLoR8BJpBngwcAtETEty7jMrPbkKow+BvwmIoZnHY8VJknA9qSkallSUnVLU0mVxBq5639A2rrZrcElk0grkIOBwREUc2auqrSZZEqiK9ARmJQ7FNmM56gzqbv0j4ETI+L2MoZoZSJpUWAIsA1wREQ83vzn0hHoTvq9aTOzLFabch+cu5D6VW0EXA5cERHjMg3MzGpCrsroY8DFubOcVgVynw07kJKkpZmbVM2a/zq2B+4lJVDtF3DbelI1x10i+LrUMVeSmj4zJbGpxE0SU0mZ8pfATInnJA7IDZQLPFebAM+Tzh1s5ESqekXE+Ig4nDSAvCXXm6fhTMq3JFaU+J3E18A0Uvf1GRIfSZwksWirBG5WYpE8lGvwuBOwIjAmd75w/YzDM7MqlttWPBoY5kSquuQ+Gx4FtiVtDT8GeFXSIZLaA0hsBtwP9GDBiRRAV2AD4J9So9WrmlKTK1MS6wO3AqsAncn/P30SMAs4OYIRc5+rjsCvSL9MJwM3+3xB7ZC0BDAU2BQ4PCKenvsYiwLXk2buAbrkucUU0u/TcOCkCNyzwaqapKVIZ6oGAv8jbc14KCKaW3nLzNq43PvIP0mrGedlHI4tpNxKVV/SStVisNT58PkQKKr1TD1wcwQ/KWWMlaTmkimJbYAHSFuzmtMkro60p/NMSRuQBtOfAj+JiLHli9SyJGl/4FLgBuBsiEWBp0gHMTs34xZ1wAuk5eu8Hd7NqkluW/PBpBXczqStsTdGRF2WcZlZZcv1dnwUeCAifpV1PFY6uaRqZzhuGPxhVVik4I621VeHV16BO++EQw9t9HA9sGwEE8sYbmZqKpmSWA94BlikZc+MOhjxKBy5OXA6MMKrUbVP0tLAZdBzPfi0C3RbkdSAubnqSdWK9opodv8Ms4o2z4HkQcDmwNWkbTueXDKz+eQq5z4MPAmc4rFTbZLiFWh6K/hDD0HXrvDBB3mTqSnALyK4tFwxZqnWzkwNJ61I5bX66lBfDzfe2PARdYMf7QGDdomI4X4zaBtyh+4PhFGvQLuVaZBIHXccPPccTJ0KI0bkvUVXYDtgn7IHa9ZKcnvn/xERewNbkcoX/0/SjbmzpGZmSOpOOkPzH5xI1SyJtUGrNnXNQQfB+PEwunATmu7AiSUOrWLUTDIlsQ7poFvBrX3DhqXBcX4dp8Gfdi9HbFbJoj3stCN0afR7M3YsnHceDG+6sGt34LRyRWeWpYh4KyKOB1YDXgHukfSYpH3nHEo2s7Yn127hXuAt4HgnUjWtNxQ+H96jB/z2t3DyyQu8z/IljKmi1EwyRcp4C1bnW3DWrK7AIKlZFUqsdvwf0CnfA3/5C9xzD3z11QLvsZHEmqUOzKxSRMQ3EXEhsCqpnPoZpCqAJ0rqkW10Ztaacucr7yJVuv2Ji9XUvCZrEJx7Llx7LXzyyQLv05zz6FWplpKpH1LgvEsLsubOwMYljssq249IZT4XRgdg34UPxayyRcSMiLiVdJbqMFLvtvck/VHSStlGZ2bllqt4fAupKeuAhn2IrCZNhPz9WTfaCPr2hcGDm3Wfmi3W1ZLD9pWuZ6EHWpA1zwaWLGVQVvFKsezckdQ53KxNyG3peQp4SlJv4ATgRUmPAIMj4pks4zOz0stt7b2BNPH8g4hwa5C24TUKrCptvz307g0ffpj+eZFFoH17WHdd2HTTRpe/Ub4Qs1VLK1N5lyBbmDVD8xqRWe0o1WugliYmzJotIt6PiFNIff2eBkZKelrSDyX5dWFWAyS1A64BlgL2j4jpGYdkrSSCT4AnyLM6ddVVsNpq0KdP+rriCrj/fth110a3mQT8sdyxZqWWPujqyLNdq4VZs4CvyxqlVZovS3CPWaS942ZtVkRMBIZIGkqqcDkI+GPun6+JiPFZxmdmxcm1S7iUVIhm94iYmnFI1vr+SNrePV/rofr69DXH5MmpAvKXjUdWs4C7yxphhmppZephaNzrpwVZM6T/Hi+WNUqrNKOAyfkeaN8eOndOf8779zymkn7/zNq8iJgVEaMiYhtgf9I51HclXSJptYzDM7MWyCVSFwObAHtGxJSMQ7JsPAJ8BMxs6qJzzinYY+r3EYUrAla7WkqmLiKtTs2nvh4+/3zuVxNZ83Tgmgg849K23EaBLaJnnpl+V844I705TJ2avpfHJ0DBovtmbVVEPB8RhwAbkj5Qn5F0t6TtcoM0M6ts5wE7kFakJmYdjGUjgtlAX9LurSYTqgbqgPtIY/SapVppDSAhUr+DYmc+pwLrR/BO6aKyaiAxFPgpTZTWb8IU4MQImu5GZWZzmnweBpxEeu38Cbjd5y/MKo+kM4F+wHYRUYot8VblJFYC/gksTSqZXsDsgHZ1wE3AcRHUdNXHmkmmACR2Av4KdG3hU6cAN0QwsPRRWaWTWA54GViCJnop5DEDGAN8zyuaZs2XO8y+O+lc1TrAMODKiFhwVzczKztJp5AmGbeNiM+yjscqh0R34BDgdFJS1YVUgyGAqTCrAzw1CbbZH3gsIn9Z9VpSU8kUgMRhwBU0P6GqA0YDP6j1zNkKk9gA+BepiElztr9OBz4jJVLjyhmbWS2TtCFppeoHpG23QyKiZkvomlU6SccBp5BWpD7KOh6rTLkdYVuQ+g0uSdrh9Tm8eS+s9RRpa+grWcbYWmoumQKQ2BMYCSHQIgUum0pahbgKGOREyiRWBx5i7vJ1nlWqWbOh/VRSoZK9I1z90awUJC0DDASOAf4DDAYeiVr8kDKrUJKOBM4mJVLvZR2PVSdJZwHLR8QxWcfSGmoymQKQ6AIjL4DNj4JV2wHTcg+1Jx2euxS4PIKxmQVpFSc307IDcGruz2mkpWvB7M5w5yzYa5uIri9kGadZrZLUhbSFZBDptTcEuNnlmM3KS9IhwIXADhHxZtbxWPWStByp2W/viJiQdTzlVrPJFICkO4C/Q8xZbegIfAO8U8slGq00JJYAViT1VZgAfAB6Ejg+Ih7PNDizGper9teXlFRtStq+fVlEuKebWYlJ2p80ydw3Il7NOh6rfpJuBZ6KiEuyjqXcajaZktSTVBN/lYjwViwrCUlnACtFxLFZx2LWVkhaB/gZcBCp8ePgiHg506DMaoSkPYFrgV0j4r8Zh2M1QtI2wDXAOhHRqA9sLamlPlMN7Qs85kTKSuxW4ABJxZRRN7MiRMTrub33q5NaYPxN0mhJe+YqA5pZAxId0pGHpq7RzsBwYC8nUlZiT5COSuyUdSDlVssfQv2AkVkHYbUldyD3TWDnrGMxa2si4quI+D2wCjACOAd4XdLAXA8rszZNYl2JqyQmkarOTpaYIfG0xA8kOsy9VtuRxkn7RcSzWcVstSlXPGgYcFzWsZRbTW7zk7Q0acC7QkRMyToeqy2Sjgc2j4gfZR2LWVuWO1e1Delc1TbA1cClEfFJpoGZtbJcNdqRwPqk8+Ed8lw2iVSA6xTQG8A9QL+IGN1qgVqbImkR4ANg44j4MOt4yqVWV6YOBO53ImVlcgewp6RuWQdi1pZF8nhE/ADYnNTS4BVJN0v6bsbhmbUKie8Cz5MKtXQlfyIFqY/iYjDrMrjoEWCAEykrp4iYDNxIanlRs2o1meoH3JJ1EFabctXE/g3slXUsZpZExNsRcSKwKqkP3F2S/iVpP0ntMw7PrCwkVgMeAXrR7DFd+y7ws/YQa5cxNLM5LgOOlNQ560DKpeaSKUkrA2sDf886FqtpI0lJu5lVkIgYHxEXAasBQ0k9496SdFKuyqtZLbmKtOL0rUmT5v+aORMuaVScukNn4PcSy7VWoNY25XqWvUTaNVaTai6ZAg4G7oqI6VkHYjXtL8AOkhbLOhAzaywiZkbE7RGxBdAf2AJ4T9KfJPXONjqzhSfRG9iSBmO5Hj3mfi27LNTXwx13FLzNT8sbpRlQ44UoajGZ6o+r+FmZRcRE4GFg/6xjMbOmRcQzEXEQsDEwC/iPpDslbZUrYmFWjY4Hmvz93X9/GDcO/vWvvA93AU6ct8KfWZncBywvadOsAymHmkqmJK0HLAHkf9swKy1v9TOrIhHxYUScCvQGHgOuB/4t6WD3jrMq1B9o8hzKgAFwww1N3qM9qXiLWdlExCzgCmp0daqmSqNLOg/oEhE/zzoWq32SugCfAutFxNis4zGzlskVptiTVFp9VeBS4OqI+CbTwMyaQaKOVL0vr5VWgnffhdVXh/ffL3ibCcDhEdxd8gDN5iFpKVLT9dUi4qus4ymlmlmZym3VcKNeazURMRW4G/hhxqGYWREiYlZE3BMR2wP7AhsA70q6VNIamQZntmBNjuEOPRSeeKLJRArSNkFv87Oyi4gvgL8CR2QdS6nVTDIFbEZqRvdi1oFYm3ILaauFmVWxiHghIg4F1iPN1j8l6V5JO/hclVWoSU09eNhhcP31C7xHAF6JtdZyKXCspFrKP2oqmeoPjIxa2rdo1eBRYCVJq2cdiJktvIgYGxG/AlYG7if1SHlB0oBa7pNiVekRUkGVRrbYAlZYockqfnN0Ap4tcVxmhTxLSt53yzqQUqqJZCq37/2HuFGvtbKImAncgQtRmNWUiKiLiCtJK1W/BA4B3pf069zef7OsXQxMy/fAgAEwahRMntzk82cCIyOaXuEyK5XcgkfNlUmviQIUkvoCf4iI72Ydi7U9krYAhgPremXUrHZJWh84idQS4U5gSES8mmlQ1qZJvA6sXeTT64DvR/C/EoZk1iRJXYEPge9HxLtZx1MKNbEyRdri51Upy8ozpH4dG2UdiJmVT0T8LyKOAtYCPgIekfSQpN18rsoyMhCoL+J5dcDdTqSstUVEPXAdcGzGoZRM1a9M5cpTjwU2jIiPs47H2iZJvwc6RMRpWcdiZq0jd4aqH6m0ekdgCHBjbrBg1iokDgWupIky6Q3UAf8Gdo1gRtkCMytA0qqk38GVauH9shZWpnYHXnIiZRkbCRxcaxVqzKywiJgWEdcBfYATgL2BDySdK2m5LGOztiOCG4EDgcm5r0KmA1OB23EiZRnKbe97Fjg461hKoRYGfv3wFj/LWET8j1ROeausYzGz1hXJ6IjYE9gGWAJ4TdL1kvpkG521BRHcDyxNSurfIK0+TYDxABNJZdQvBdaN4AgnUlYBhgHH18IW6are5iepJ2nf+qq11k3Zqo+kM4DvRMTArGMxs2xJWhw4GjgeeAsYDNwXEbMzDczaBInVgGVg+yfhn32AMRFMzTgss2/ldvK8BRwSEc9kHc/CqPZk6lDghxGxV9axmElahbRsvXxEeNbPzJDUkbQFaxCwKPBn4LqIaLpotVkJSIqIqPqZf6tNkn4ObJRrmF61qn2bX3/SWRWzzEXEe6RZlr5Zx2JmlSEiZkTESGAz4AhgB1K/qgslfSfb6MzMMjUc2FPS0lkHsjCqNpnKNU3cErg361jM5nELKck3M/tW7lzVExGxPymx6gi8JOlWSd/PODwzs1YXEV8Do4Ajs45lYVTtNj9JA4GtI8IDV6sYkpYhHf5dISLqso7HzCqXpF7Aj4ETgU+BPwF3R8TMTAOzmuFtflbpJG0C/IVU/2BW1vEUo2pXpvAWP6tAEfE56dzUnlnHYmaVLSImRMRgYA3gYtK5qrclnZxLtMzMalpEvEDqF1u146aqTKYkrQysDfw961jM8vBWPzNrtoiYGRF3RcRWwA+B7wHvSRqSa25pZlbLhgHHZR1EsaoymSI1+borIqZnHYhZHn8BdpC0WNaBmFl1iYhnI6IfsBEwDXhW0ihJ29RCPxYzszzuADaStFbWgRSjKpIpic4Si0m0z33LjXqtYkXEBOARYD8kIXVDWpTUU8HMbIEi4qOIOB3oDYwmVb16TtIhkjqV4t8h0SH32dq5FPczMytGREwDrgUGAkhIYhGJHhIVP4lUsYM7iVUkLpaYQOrk/RkwQ5r+CZyyMvzvv9lGaFbYMfDkvXAu6Xd3IvA5MAPpZaRDkDx4MbMFiojJETEMWAs4h1T16l1JZ+QaA7eIRC+JEyU+AKaTPlvrJCZIXCSxckl/ADOzZulyBfQ9XJrxd2AG8A3wFTBDYrTEblJl5i0VV81PYingZmAbUrKXZwZu2gzoPBO4Ajg1gqqs/mE1KC1R3xqw5kzo1jH/VZNyf/6KiKGtFZqZ1QZJfYCTgH2AW4EhETGm6efQAbgIOBqYDXTPc9k0IIDHgEMi+Kp0UVsWXM3PqoHEDsD1UL88dGkHebc0TwKmAEdFcH/rRti0ikqmcjNiTwFLkjeJaqQOeBLYMwKfn7JsSZuRtvd1p3mrvnXACOAEKumFaGZVQdKypG0xxwDPAYOB0dHg/SS3je8BYHOgWzNuPR34Atgigo9KGrS1KidTVukkDiKNhbo28yn1wM8iuLp8UbVMxSRTEosBLwIrwrdno5qjDrgPODiCyvhhrO2RVgf+A/Rs4TOnAH8g4rzSB2VmbYGkrsCPSKtVs4AhwMiImJo7b3AnsDvNH6wAzAQ+AjaJYHwp47XW42TKKpnEjqQxfEvemyAlVP0iuKf0UbVcJe09/DWwLA0SqX/8A+rrYdKk9PXGG42e1w3YA+jbKlGa5XclsEij7y62GIwaBZMnw/vvQ79+Da/oDvyKVO7fzKzFIqI+Iq4G1gdOJZVXf1/S2fDyD4FdaTBYOe44eO45mDoVRozIe9sOwPLAL8savJm1SbnzTzeTJ5G68UYYOxYmTIAxY+DIIxs9vStwvdSsXWxlVxHJlEQX4CjIX1Ho+OOhR4/0tfbaeW/RHfh5+SI0a4LUG9iSfK+nYcNg+nRYZhk45BC4/HJYd91GdyBXwcbMrFiRPBQRuwE7AivANzeR53zU2LFw3nkwfHiTt+wM/NTV/sysDHYl/9lNzj8feveGXr1g773Te9UmmzS6rB2wX3lDbJ6KSKaAAxfy+QK2lVixFMGYtdBAyFO6s1s32H9/+PWvYcoUePJJuPdeOPTQhld2Bo6hROWOzcwi4jWI38G2eQs0/eUvcM898NWCS0yIChmwmFlNOQ3oke+B115L89AAEelrtdUaXdYDOL2M8TVbpSRTh1LgPyikDPWLL+CJJ2C77QreYzawdxliM1uQfuRbVV1zTZg5E956a+73XnoJ1luv0H22KkdwZtZm7Q1a2LPEPUif0WZmJZFb7d6mqWuGDUvz0GPGwKefwgMP5L1sHYklyxFjS1RKMrVMoQdOPx1WXRVWWAGuugr++tf0z3l0gez/g1qbtGje7y6yCEycOP/3JkxI+1Xz8++vmZXSUqTPxoVV8DPazKwIi0HTVbiPOy4Nl7beOh09nzYt72XTqYCxU6UkUwWr9z37bDq7P3063HBD2im1xx55LxWV8/NY25L/927yZOjZoLhfz56pkkpL7mNmVpyWVMZtjfuYmUEz31Nmz07j/hVXhGOPLXhZ5mOnzAPIaXZjwIgCrbxSs8FvShWQWQtMzPvdN9+EDh1g9dXnfm+jjeDVV/NdHfj318xK6ysWMPvbgvuYmZXK1zSvnyyQhlJ5zkwBdKQCxk6VkkyNIvWLmk+vXrDLLtC5M7RvD/37w7bbwoMP5r1HAA+XOU6zfP5G6skyv7q6tDb929+mYhRbbgn77JNqfjbWCXi6zHGaWdvyMETj9ybSZ+qcz9Z5/57HFOCucgZpZm1LBPVA3pnlpZaCgw6C7t2hXbuUB/TrB6NH573VZ7mvTFVKMnU9eWLp2DGVQ/ziC/jySzjhBNh33/nP88/j1QheK3OcZvkModDs78CB0LUrjBsHt9yS1qlfa/RrOhO4hYiC+//MzFpCUi/QzvBax3yPn3lm6jF1xhmpwOjUqel7ebQDbipnrGbWJl0ANBr3RKSh0scfwzffwEUXwUknpZoJDUwBLoxgYYvsLDRFZB4DABI3AP0pbm/2ZODHEdxR2qjMmkl6EehT5LPrgM2JeKV0AZlZWyRpVeBE4DDgIXjgVdj9dPI1FV+wmcANETRumWlVQVJERP7DEWYZylX0Gwf0XNC1BdQDy0Q0TshaW6WsTAH8mjwZajNMA14D7i5pNGYtM5A8W1WboQ64y4mUmRVLyTaSRgHPklbK+0REP9j9AmAMxZ2dmgScU8JQzcwAiGAaaeKn2LHTLyshkYIKSqYi+ADYhfTm3dzlsqnAB8BuEcwoV2xmCxTxNKkXS0veFOqAp8CzvmbWcpI6SjqElEANBx4FekfEaRHxIUDus3EX4EPS5GNzzCYV1ukbwYelj9zMDCK4nrTdr6Vjp6siGFKWoIpQMdv85pBYh3Sgf3HStoQ8y9OzZkP7acATwP6VkpmaIe0I3BXQXoUbUU8jTRjcBBxL5D8gbmaWj6TFgaOB44G3gMHAfRExu/Bz6EUqJLEFqeBNhzyXBekcwpekScoxJQ7dWpm3+Vk1kDgKuASmdoQu+d6bICVR7YAzI7i49aJbsIpLpgAk2gF9gVNJHZLnDD7bwaxOcGs9/HDriI55K4GYZUrqdCuctREMWie98Kfz7e8vs4HLgcuI+CjLMM2sukhaC/gZ0A+4FxgSES+27B6sD5xEOqM8k/SeJKAz8DhwIfBoBAUTM6seTqasWkjHrQwdXoc/fQXtF4dvd5x1BMYDFwHXRWRfCr2hikym5iWxFLA80A2YAF98AEu/Auzf0g8Rs9YiaTjwSsDtwDKkmeDxwLtElKLvi5m1AZIE7AgMAjYDrgQui4hPF+6+dAd6A71Iq1GfRPDlwkVrlcbJlFULSacCG0AMAFYBliBN9HwNvFvJEzwVn0zlI+l3QKeIODXrWMwaktQFGAusHxFjs47HzKqPpM6k1aOTSDOzg4GbIqI+y7isujiZsmogqT1py3K/iPh31vG0VMUUoGihW4CDJVVr/Fbbdgf+60TKzFpK0tKSziYVVzoIOB1YLyKudiJlZjVqN+ArUjGdqlOVyUhE/A/4Btg661jM8ugPjMw6CDOrHpLWl3QtqYz5CsBOEbFbRDwY1biFxMys+Y4DhlXre11VJlM5I0mDVrOKIaknqQzxXVnHYmaVTVI7SbtL+jvwMPA+sGZEHB0RLrBkZjVP0mrA94Dbso6lWFV5ZgpAUm/gOWCF8IF+qxCSDiMVR9kn61jMrDJJ6kbqS3cSqVrtYODWiGhuHyizZvGZKat0ki4CZkfEaVnHUqxCtdwrXkS8L+lNYGfg/qzjMcvpD1yXdRBmVnkkLU/aznI08DQwEPhntW5tMTNbGLmJpcNJK1NVq5q3+UEqRNEv6yDMIB0cBzYH/pp1LGZWOSRtIulG4FVSKfItI2LviPiHEykza8MOBp6JiPeyDmRhVHsydQewZy6zNcvagcD9ETEl60DMLFuS2kvaV9JjwD3AK8CqEXF8RLyVcXhW4yTaSywOSyPROet4zBrK9dA7HhiWdSwLq6qTqYj4HPg3sFfWsZiRVkldxc+sDZPUQ9KJpKp8ZwCXk5KoCyPim2yjs1omIYnNJe4A6oFP4T2AOonXJQ6X6JptlGbf2hzoCTyUdSALq2oLUMwhaQCwnw/8W5bmKYiyfETMyDgcM2tlklYGTgCOAB4lFZV42tv4rDVIbADcSSqr35X8k+WTc3+eDQyOwL+blhlJNwEvRsTFWceysGohmeoJfASsEhFfZx2PtU2SfgH0johjso7FzFqPpC2AQUBfUvGZodW+/9+qi8S2pEJc3YHmVO6rA24ABjqhsizkzpiPAVarhbF7VW/zA4iIiaT+HPtlHYu1ad7iZ9ZGSOog6YeSngZuBp4iTaac7ETKWpPEuqREahGal0gBzCnNf1a54jJbgKOAu2ohkYIaSKZy3MDXMiNpPWBx4ImsYzGz8pG0qKSfA++QtvT9EVgjIobkJvbMWtvVpBWp+ay8Mtx/P3z9NXz6KQwdCu3bz3dJd+AXEiu1UpxmQJqMAo6hBgpPzFErydQDwMa5Hh5mra0fqeHm7KwDMbPSk7SapEuAd4GNSY25t4mIURExK+PwrI2SWAPYhDwrUpddBuPGwXLLQZ8+sN12MHBg41uQep2ZtaY9gY8j4sWsAymVmkimImIqcDdwUMahWBuTK+3Zj9TzzMxqhJLtJN0NPANMATaMiEMi4vlsozMD4ESgfb4HVlkFbr8dpk2Dzz+HBx+E9dZrdFln4FiJTmWO02xex1FDq1JQI8lUjhv4WhY2A2YANTPDYtaWSeok6VDgP8BVpLK9vSPijIj4ONvozOZzINAx3wNDhsDBB0PXrrD88rD77imhKmDzMsVnNh9Ja8G3lSdrRi0lU48CK0taI+tArE3pD9zi8sdm1U3SEpJ+SWrMMwD4NbBORFzuRtxWoXoWeuDxx9NK1MSJ8Mkn8PzzcPfdBe+zRDmCM8tjIHBtREzLOpBSqplkKiJmArfh1SlrJblDlAfhLX5mVUvS2pKuAN4GVgd2j4i+EXG/z0FahctbvU9Kq1CjRkH37rDEErDYYnDBBQXvUzNjQatckhYhVZG8MutYSq3WXkC3AP1z51jMym174KOIeDPrQMys+XLnoXaW9ADwGPA5sHZE/DgiXs44PLPmmpTvm4svnqr5XXopTJ+eKvqNGAF77JH3HgHURHlqq3g/Ah6LiA+zDqTUai2ZeoZ0oLJPxnFY29Afr0qZVQ1JXSQdCbwMDAbuAlaOiLMj4vNsozNrsQeAmQ2/+dVX8O67cOyxqRx6r14wYAC8nH+aoAPw7zLHaW1cbpGj5gpPzFFTyVTu3IoLUVjZSeoC7EvaWmpmFUzSMpLOAT4A9gdOBjaIiGtz1WDNqtGfgOn5HthvP9htN/jiC3j7bZgxAwYNanTZDOC6COrKHKfZNqRiKaOzDqQcVGvn5iWtD/yNNNvo/e5WFpJ+AJwYETtkHYuZ5SdpQ2AQcyc+/hwRr2calFkJSfwX2KjIp9cDfSLwVnUrK0m3AU9ExNCsYymHmlqZAoiI/wHjga0yDsVqWz9gZNZBmNn8JLWTtKek0aSJtbeA1SPiGCdSVoOOgWJWlmbVA9c7kbJyk7QcsDNwQ9axlEvNJVM5I0nnWcxKTlJPYFfSeQszqwCSuksaCLwOnAOMAFaJiN9HxFfZRmdWHhE8AxxCWmVqppnT4KF2sGjNVVWzinQ0cFtETMg6kHKpuW1+AJJWAZ4Flo+IGVnHY7VF0mHAARGxd9axmLV1klYEjgeOAv5FKizxL/d+s7ZEYjvSBF8noEeBy+acD7wCOj0NM4YAO3nF1spFUkfgfWDX3M6xmtQh6wDKISLek/QWaVnxgazjsZrTjxperjarBpK+SzoPtTtwE7B5RLydbVRm2YjgMYllgb2A00lVjaeTSp93IG0F/DNwdQSfw3QkdQYelrS9XztWJvsCb9dyIgU1ujIFIOl40ofrj7KOxWqHpKVIZzBWiIgpWcdj1pZIag/sQ0qiVgKGAtdExPgs4zKrNBJLAkuT2sV8A3wUwazG1+knwK+A7SLig9aN0mqdpH8Cl0XE7VnHUk61nEwtA4whbfVz2U8ridyZjK0i4pCsYzFrK3LnFH8MnEhqsDsYGBURjXrsmFnLSDoB+Bkpofok63isNkjaAHiIVF27po/c1GoBCnINGP8N7CUhiUUkFpNq92e20pPoLLGERMfct9yo16yVSOot6U/Ae8AWQP+I2CIibnciZVYauXLVVwGjcxPRZqUwELiq1hMpqOFkKjn2aXj4YtKhy6+Bz4AZEi9IHCTRKdv4rBJJrCTxB4lvSPvMPwGmSTM/g1/0gcefyzZCs9qlZCtJdwL/AWYBG0fEQRHxTMbhmdWkiLgQuJV0hmqJrOOx6iapF3AwKUmveTW5zU9iQ+A2iJVgdjdon++yScBs4OcRXNOqAVpFkliMdJB9R0CkveYNTJsJnWcC1wMnRuTvPm9mLZOr+rQ/cDKwOOmw/HURMSnTwMzaCEkC/gD0JVX5G59tRFatcltHt46Ig7KOpTXUXDKVKw96P9CNNCBekDrgkgjOKGtgVtEklgOeBpaDZq1Y1gH/BfpGtKS/h5nNS9JiwE9I5c3fJZ2Hui8iGh2WN7PyyiVUQ4DNgF08mWFNkpYFvg8sCswAPn8b/rUGvAT8NCIezzK81lJTyZTE+qQB8SItfGod8KsIhpQ8KKt4EouQthOtSsvaBdQDjwH/F8HscsRmVqskrUE69N4fuA8YEhEvZBuVmeUSqiuBtYDdXcTL5pN+P7YBfk5qQTSddGwogJgB7S+HuqNhky4RH2cYaauptTNTw4Hu+R446CB47TWYPBnefhu23nq+h7sB50v44GXbdAqpzPJ8idTaa8Po0TB+PLz1Fuy7b6PndQW2JvVRMLMFyJ2H2kHSvcCTwHhg/Yg4zImUWWXINbw+BvgAuFtSl4xDskoh9QAeJe0A2xPoAvQkLWL0AHp2hO4DYdEu8BZpu1/Nq5lkSmIdYH3ybO3r2xcuuACOOAJ69IBtt4V33210iyBtNbE2RKIDqdzyfB8W7dvDPffAfffB4ovD0UfDTTfBGms0usUiwGmtE61ZdZLUWdIA4AXgMtJKVO+IODMixmYbnZk1FBGzSe0IxgN3SHLBrrZOWoS0+2tz0tin4FGaDtCRNK46H+ms1gkwOzWzzU/iStILv9E2rSefhGuvheHDF3ibL4Fl8zW2s9oksS9wA2lG5VvrrQfPPJOS7zkeegj+/W84q/HbQj2wcQRjyhqsWZXJNbk+hlQi9xXSeaiHcgM1M6twucIwd5LOwxzslgRtmPR30va+lq5U1gFHEnFr6YOqDDWzMgUcQJ5Eql07+O53Yaml0latjz6CoUOhS/5fhc7AxmWO0yrLITRIpAqRYP318z7UAdinhDGZVTVJ60m6GngTWBnYOSJ2iYi/OZEyqx65HkE/JK1EXCcpb3lkq3HS94AtaZhIdeoE11wD778PEyfCiy/Cbrs1fHY34GKkWso55lNLP1jPfN9cZpn0//qAA2CbbaBPH9h4YzjzzLz3mA0sWcYYrfIsn++bY8bAuHFw6qnQoQPsvDNstx1065b3Hh2BZcsZpFmly52H2k3SQ8AjwEfAWhFxVET8L+PwzKxIETEN2A9YAbhSNTwotoJOIZ0Tn1+HDmmVYrvtoFevNLi+/XZYeeWGV/YktZ2pSbX0gsi7d7M+V7R66FD47DP46iv4059gjz0K3sezLm1L3tfAzJmp4MT//V/6vTnllPT+8HHhujQtqQJoVjMkdZV0NPAqcAFwC+k81G8jYly20ZlZKeQq+u0FrANckqv4Z22BtDhp903j8VJdHZxzDnzwAUTA/ffDe+/Bpps2vLI7cGr5g81GLSVTU/J9c/z4lDTPezSsiWNiAr4ucVxW2b4o9MArr8D228OSS6ZV61VXhWefzXvpLODzMsVnVpEkLSfpXFLFr71IfaL6RMR1uZlsM6shETEZ2IPUV+hCJ1RtRh+gee/pSy8Na64Jr77a8BGRfm9qUi0lU3+H/L1+RoyAE05I56YWXRQGDUpV2vJoB7xYvhCtAo0CJud7YIMNoHNn6No1rUwttxxcd13ee0wl/f6Z1TxJfSRdD7wGLE7qcr9XRDwatVLRyMzyiogJwK7ALsA5GYdjrWNRmqjc960OHeDmm+H669NZicbyH5SoAbWUTF1MqqrWyLnnwnPPwZtvwuuvp/Nxv/tdo8umA1dHMLXMcVplua3QA4ceCp9+ms5O7bRTOjc1fXreSz+O4LmyRWiWMUntJO0t6R+ksuavA6tFxHER8WbG4ZlZK4qIr0nNWg+QdEbW8VjZTSO1DypMghtvTIOk448vdFXNVoKspdLoIlWOWr24O8yYBf/ZKGLzRmuTVtukd26D7xwInYrZsjAFOCGCEaWOyyxrSn1FDgd+Ruo3Mxi4I1fhy8zaMEnLA48BwyJiSMbhWLlIm5D+Py9S8Jrhw6F371SQYGrBNYlPiFix9AFmr2ZWpiII4GgKrE4t4Nl1cP9bsMU9krYudWxWmXKNRM+DbXeE2ZObPE2X33TgXdKBe7OaIek7ki4E3gd2AI4ANouIkU6kzAwg13B7J+Bnkn6adTxWNi+SJtPyu/xyWGcd2GuvphKpqcDVpQ+tMtRMMgUQwT9oeUI1BfR32Hd9UunH2yVdLKlxCUirGZL6AM8BG8DYDaDLlqAJFDh3l8c04FNgJ28NtVohaTNJtwIvkUr+fy8i9o+IJ3weyswaiogPgb7AmZIGZB2PlUF67/8j+Qq9rbQSHHNM6jv02WcwaVL66t8/352uLG+g2amZbX7zktiDtFogCjdknZp7/DLg5xFpEC1pSeBSUvWSARHx77IHbK0m1839DFLlsZ8DN84ZJEqsCjwILEcq45lv299M0orU88C+EXzTGnGblYukDsC+wCBS37VLgGsjYmKWcZlZ9ZC0NvAoMCgiCp5Ftiol9QLGUlwRiRnAg0TsXdqgKkdNJlMAEp2BA4DTgDVJA+Ag9ZGaThowXBnBZ/mfrwOBocAI4Dcu9Vv9JK0PXAd8CRwVEY26RuXO3m1L6ofQl7kHL9uRekndBgyO4OVWCtusLJQ+HI8ETgQ+Jp2HuiciavaQsJmVj6QNgIeBYyLi7ozDsVKT9gNuIl/z3sJmk1rQbEREzbaQqdlkal4SKwBLA52Ab4B3IxZcVUTSMsDlpGRsQET8p6yBWlnkZt5/TtrGeQZp1n2Bv/gSi5M6vncHJgIfRuQvo25WLSStSkqgDiOtxA6JiPwd1MzMWkCpWMHfgMMj4m9Zx2MlJh0BDKN5CdUM0uT1tkS8Xda4MtYmkqmFkWtK1580a3s58LuIyF8g2yqOpLWA60l7fX8cER9kHJJZq8u9j21N2sq3LXANcGm+1Vkzs4UhaXPgXuDgiHg063isxKQdgSHAakBn0o6vedWRdvPcA5xIxLhWjS8DTqaaKVcC9GrSmYIBEeFtXhVMUntSOedfAmcDl0dEc4tLmNUESZ2AA0lJVE/SB+D1EdH4ILGZWYlI2g64E/hBRDwx9/t0BX4I/Ii0Y6gd8BVwO3BjBJMyCNeKkQp5nQzsSKpPMJO0EnUNMJyIr7ILrnU5mWqB3Ozu4cCFpEHJBT5fUHkkrUY6GxXAERHxTrYRmbUuSYsDPwWOI/XfGwzc7wkFM2stknYhnbHZE+Jt4CzSOU1o3LNoCimxGgn8JgKvmlvVcDJVBEkrkTLvRUmrVK9nG5EBSGoHHAucA/wO+LMHj9aW5La1ngQcTNpiMSQi/ptlTGbWdknaC1YfAa/OhE6Lkc6uN2Um6YzyThH8t+wBmpWAk6ki5VapjgbOAy4ABkfErGyjarsk9QauJRWLGBARY7KNyKx15N6LdiJt5fsuqZfHZRGRt1KpmVlrkVgW6t+ATr0aH60pKEgJ1fcieKt80ZmVhpOphSRpFVL59I6k6jV+4bei3EDyKOD3wEXAxd56aW2BpC5AP1IS1Z60le/miGhJ03Izs7KReAzYgjRGaonZwLvAmhF4oGoVrV3WAVS7iHiPdPjuNuBpSSfmtptZmUlakVSC9Rhgh4jwGTareZKWlnQ28D7pIPfPgfUj4honUmZWKSTWAr5HnkRq7bVh9GgYPx7eegv23bfR09sBywLblDlMs4XmQX8JRMTsiLiENPtyEPBobsXKykDJAOAF4Elg84j4X8ZhmZWVpPUlXQuMIVUV3TEido+Ivzenb5qZWSs7kdTsfj7t28M998B998Hii8PRR8NNN8EaazR6fnfSZJFZRfM2vxLLleQeBJwO/Bq40gOd0pG0LHAVsDLpbNR/s43IrHxyq9y7kd5T1gMuA66IiC8zDczMrAkSAiYD3Ro+tt568Mwz0KPH3O899BD8+99w1lmNbjUNWCaCCeWL1mzheGWqxCJiVkRcRGqM+WPgIUnfyTisqpdbjeoHvAS8DHzPiZTVKkndJB0DvEqqTHkjsEpEnOdEysyqQA9acE5KgvXXz/vQdGC5EsVkVhaNll+tNCLidUlbAqcBL0g6HRixoFUqiW6kylxLk/7/fA08EcGn5Y65nHKzVFuQOmYvAkwCXgdeWNDhUklLAZcD6wJ7RsRzZQ7XbMFSBcnNSS0SpgGfAaOJmF78LbU8cDzwE+ApUqn/x7y6bWZVpjupzHmjhGrMGBg3Dk49FQYPhh12gO22g3/8I+99ZpNndavqSHnHdkRU9djOEm/zawWSNgSuBz4Bjo6IsY2vYS3gZ8AA0htQe0C5v3cGHiZVq3u8mirbSPQCDgNOBRbLfbsdMCv35yek0vK3RlDX+PnaDxhGmpk/KyKmtkbcZnmlbby7kiZJvg/MIL1Wg/Q7DXAFMIyID5t/W21C2sr3f8DNwCWuDGpm1UqiK2nSNG899A02gKFD02rU88/DF1/AtGlw1FENr5wSsNVoeOlF4A3SmdExVbNCn3r/NWtshwfkVcvJVCuR1BH4FWmm+WRgZEREbsXmt8AppNmKQsviQeoQ/jTwgwimlD/qhSOxNXA/6c2jexOXTgamkpr0vZyeq8WBS0l9cw6PiKfKHK5Z06QlgL8Da5JWVwuZRnq9nkLEZYVvp/bAXqQkahVgKHBNRHxTspjNzDIiMZZmbtF78km4/nq46qqGj8yqgxWOhM9XBdYC1s79OZNcYpX7mpNovRMRM0r0IxQvtW1p8diOiIof21ljTqZaWW4G+gbgTeh2LEz5DXAoTScb85pKetPYMoKKLYMssSPwV5q/PD/nDWU70PKkxqN3AL+MiEYrVmatKiX3/yFV0evUzGfVAb8j4vfz30o9gCNIs5VfkPpDjaqIAYCZWYlInAr8hjzjgA02gDffhHbtYOBAOO64VC59+vybpKcDV0Zw4vz3lUjb5eYkVnO+1gZWBD5knlUs5iZbX7bKlukU32UUObbDLS6qjpOpDEjqDJwNpxwHf+gMHTq38Bb1wMMR7FOG8BaaxOrAizQ9e1/A5Omw1mcw9rCIeKzUsZm1WPpgfBbYkOYnUnPUAz8iYpSklYETSInUaGBwRDxd0ljNzCqExBLAx0CXho9deGHa0texI/zrX3DCCfDOO41uMRXYIIK3m//vVGfS2ex5V7Hm/D2YfxVrztfbsRBnXfMEcQJwPs1PpOaoBx4moiLHdlaYk6mMSHSCmV9Bh/kSjkmT5r+ua1e47DI48UQaqge+G8Fr5YyzGBLXkvYHz7dXeuWV08+yxRZpb/Sdd8JJJ8GsWfNeNX0WzLgoovsvWjFks8KknYC7aTg50KlT+oXu2zc1S3nnHTjjDHjwwfkuq4dPu8MTkQ4fjwCGRsQHrRS9mVlmJC4jjQdaWkRiKmnSeO/SxCEBSzF/cjXn7ysBH9F4y+AYYFyLVrOkTsA4oFejxxZbDK69FnbZBb78Mn1e3HJLw6vqge8SUXFjOyvM1fyy8wPo0OgFOm/fhe7d4bPP4I478j6/I3AScHR5wiuORE+gH3kOnV52Wargs9xysOii8PDDaXl/6NB5r+rUHjr9VOLXEXjbk1WCU8k3w9ihA3z0USpD9eGHsMcecPvtaf/KB3Nzpdmw7LEw9jLoHRGTGt3HzKx2/YzUI+97QNdmPmca8C5pLFESuYRoXO7rX/M+ppQAzVnNWotUefiI3N/bS5o3uZrz97cjYlqef9W+FGo7NGxY2se4zDLQpw/cfz+89BK8Nl/eVJFjO2uaV6YyIvEfYJOmrjnsMDj7bFhttYKX1ANLRzC5xOEVTeI4UnW+RoPP116DU06Bv/0t/fOFF0LPnnDMMY1uMwk4IoK7yhut2QJIKwBvk2ebSl4vvQTnnAOjRn37rYDZgr8SsW9ZYjQzq2ASXYDbSKvzC9r6NpnUS3KPSmjUK2lJ8p/NWplUjXi+RGsaDO0EGzS6Ubdu8M03qXzhW7lCrTfcAJ98klao5lcPLE1ExYztrGlu2pudDRd0wYAB6bXWhBmkF3Yl2YECb5ZDhsDBB6eti8svD7vv3mhH1Bw9gC3LF6JZs21KmiVdsKWXhjXXhFdfne/bSu+zm5c+NDOzyhfBVNKKzYHAP0hb+OpJZ5hinn9+lrQlcLtKSKQAIuLLiHgiIq6NiNMiYp+IWIs0TtmDVCzrM2Az4HfKl0hB+myYOXNuIgVp8m299fJdXYljO2uCt/llIJ2XajqRXWmltHvoyCObvFWQGoZWksULPfD443D00TBxYtohdd11cPfdBe+zdBliM2upXhTokzKfDh3g5ptTbd8xY/JdUUQxFjOz2pDrj/k34G8SvUk99ZYkjYW+Av4ewRvZRdgyueqrc1ak7gXmnJeqJ9/4bpFF0uBnXhMmzH+2Y57bU3ljO2uCV6ayMXNBFxx6KDzxBLz/flNXje8FWz0iKSrlCx7YIV+kUlqFGjUqnQVbYol0FvOCCwr+cO61YJVgGjC7ySskuPHGtBf++OMLXVW6SlFmZlUsgvcjGBbBORGcHcEl1ZRINaHw2G7y5HSuYV49ezauOjbX1JJFZWXnZCoDEcyGppewDzssTXI3bdF6eHK1iFClfMEew4BZDSNdfPFUze/SS9OY8+uvYcSIdGY/j+mAq51ZJfiE1K2+sGuvTQeK998/bePIb1ypAzMzswoSUXhs9+abaQfD6qvP/d5GGzXaFp7TCfi0DBFamTiZys51FJit3mILWGGFglX85vV2BO+WOK6FNZw8Z0y++grefReOPRbat4devdKZsJdfznuP2cDIMsdp1hxPQxPNsS+/HNZZB/baC6YWnEicAlxehtjMzKyyjCDf2K6uLm3N+e1vUzGKLbeEffZJuxoae5uIShvbWROcTGXnUgpsHxowIL3mJjddx2USqWpeRYngBeD9fI/ttx/stht88QW8/TbMmAGDBuW9zVMRXpmyCpBmGv9EvoRqpZVSKco+fVIPg0mT0lf//g2vbA8scJ3ZzMyqXsGxHQMHpgpc48al/lLHHtuwLDpU6NjOmubS6BmSeBTYhuIKgUwAloloZqWxViTxI+AKWt79G9Is/n4R/L20UZkVKZXG/ZDm90iZ1zTgNiIGlDYoMzOrSNJoYFsWYmxH/h5WVqG8MpWtHwHjSZVbWqIe2LcSE6mckcBDNLU9Kr864AYnUlZRIr4kleuta+EzZ5LOXJ1Y8pjMzKxSHcpCjO2cSFUfJ1MZimAsaWXqC1JfgeaoA/pF8M9yxbWwcgU2+gOP0vyqfFOAO4ATyhWXWdEi7gB+RvMnCKaRVrO2JaIi+qWYmVkriCh6bEfEP8sVlpWPk6mM5cqBbgSMIpXCzDf7PSP32JOkZnb3tF6Excmtmu0NnEvqIZGv/mfkvv8pcApwRETjSoBmFSHiGmBP4CVSUpWvdN+U3GM3AJsQ8UnrBWhmZhUhosVjOyIqfmxn+fnMVAWRWAL4MWlL0ZKkg+sTgQeAP0fwdobhFU2iA6lB3yBgNaAbadD5Gulw/yO51Syz6iBtAJwMbAf0JFVvGkc6K3gzEQWbh5iZWRsiNTm2I6Iqx3Y2l5MpMzMzMzOzInibn5mZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkVwcmUmZmZmZlZEZxMmZmZmZmZFcHJlJmZmZmZWRGcTJmZmZmZmRXByZSZmZmZmVkRnEyZmZmZmZkV4f8B/cKouf7+nE8AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 1080x288 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Gnerate a connected graph with 10 vertices\n",
    "n = 10\n",
    "G = nx.Graph()\n",
    "G.add_nodes_from([0,1,2,3,4,5,6,7,8,9])\n",
    "G.add_edges_from([(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,0)])\n",
    "    \n",
    "k = 9 # Set qubit (vertex) limit\n",
    "S = NaiveLGP(G,k) # Partition G into two subgrahs once\n",
    "sep_node = list(set(S[0].nodes).intersection(set(S[1].nodes))) # Obtain seperation nodes of the partition\n",
    "\n",
    "# Show graph illustration\n",
    "options = {\n",
    "    \"with_labels\": True,\n",
    "    \"font_color\": \"white\"\n",
    "}\n",
    "node_color0 = [\"red\" if i in sep_node else \"blue\" for i in range(n)]\n",
    "node_color1 = [\"red\" if list(S[0].nodes)[i] in sep_node else \"blue\" for i in range(len(S[0].nodes))]\n",
    "node_color2 = [\"red\" if list(S[1].nodes)[i] in sep_node else \"blue\" for i in range(len(S[1].nodes))]\n",
    "\n",
    "fig, ax = plt.subplots(1, 3, figsize=(15, 4))\n",
    "for i, a in enumerate(ax):\n",
    "    a.axis('off')\n",
    "    a.margins(0.20)\n",
    "nx.draw_networkx(G, pos=nx.circular_layout(G), ax=ax[0], **options, node_color=node_color0)\n",
    "nx.draw_networkx(S[0], pos=nx.circular_layout(S[0]), ax=ax[1], **options, node_color=node_color1)\n",
    "nx.draw_networkx(S[1], pos=nx.circular_layout(S[1]), ax=ax[2], **options, node_color=node_color2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that in our case, both subgraphs are under the qubit limit and can be directly solved by QAOA. But if the subgraph still exceeds the qubit limit, we will recursively do LGP through recursively doing DC-QAOA."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Graph Reconstruction (GR)\n",
    "\n",
    "Once QAOA is applied to partitioned subgraphs, we should combine the solutions for the parent graph. Note that since two partitioned subgraphs share some set of nodes, we need to make sure that the labeling sets which these nodes are in are consistent. For example, if in one subgraph, the shared nodes are all in $S_0$, while in the other subgraph, some of the shared nodes are in $S_0$ and some are in $S_1$. In this situation, corresponding solutions cannot be combined. So we provide several possible cuts for each partitioned subgraphs to avoid failure for the combination. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:51:47.629119Z",
     "start_time": "2021-05-11T06:51:47.585155Z"
    }
   },
   "outputs": [],
   "source": [
    "def GR(str_cnt1, str_cnt2):\n",
    "    com_cnt = []\n",
    "    n = len(str_cnt1[0][0])\n",
    "    com_index = []\n",
    "    for i in range(n):\n",
    "        if str_cnt1[0][0][i] != \"x\" and str_cnt2[0][0][i] != \"x\":\n",
    "            com_index.append(i)\n",
    "    \n",
    "    for (str1, cnt1) in str_cnt1:\n",
    "        for (str2, cnt2)  in str_cnt2:\n",
    "            # Check equality for each bit in common nodes\n",
    "            validity = [str1[i] == str2[i] for i in com_index]\n",
    "            if False not in validity:\n",
    "                com_str = [[0]] * n\n",
    "                for i in range(n):\n",
    "                    if str1[i] != \"x\":\n",
    "                        com_str[i] = str(str1[i])\n",
    "                    else:\n",
    "                        com_str[i] = str(str2[i])\n",
    "                com_cnt.append((\"\".join(com_str), min(cnt1, cnt2)))\n",
    "\n",
    "    # Sort string-count map by counts in reverse order\n",
    "    com_cnt.sort(key=lambda tup:tup[1])\n",
    "    return com_cnt[::-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We still take the above example for illustration. For two subgraphs partitioned above, we apply QAOA to find their approximate max cuts and then use GR policy to form the max cut for the original graph. The code presented below has achieved this. Note that there is a parameter $t$ controlling how many possible cuts are kept, and if this $t$ is larger than $2^k$, all cuts are provided and the combination can definitely happen. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:52:48.693469Z",
     "start_time": "2021-05-11T06:51:47.651060Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Max cut for the first partitioned subgraph: \n",
      "{'010xxxxxxx': 0.49999449162430293, '101xxxxxxx': 0.49999449162430293, '111xxxxxxx': 2.420265869021529e-06, '000xxxxxxx': 2.42026586902126e-06, '001xxxxxxx': 1.5440549138418965e-06, '011xxxxxxx': 1.544054913841822e-06, '100xxxxxxx': 1.544054913841805e-06, '110xxxxxxx': 1.5440549138414785e-06}\n",
      "Max cut for the second partitioned subgraph: \n",
      "{'1x10101010': 0.14011845299520345, '0x01010101': 0.14011845299520342, '1x01010010': 0.04249785377879293, '0x10101101': 0.04249785377879292, '1x01011010': 0.0424978537787929, '0x10100101': 0.042497853778792886, '0x10101001': 0.036328002709709185, '1x01010110': 0.03632800270970918, '0x10110101': 0.03632800270970918, '1x01001010': 0.036328002709709165}\n",
      "Combined max cut for the original graph: \n",
      "{'1010101010': 0.14011845299520345, '0101010101': 0.14011845299520342, '1110101010': 2.420265869021529e-06, '0001010101': 2.42026586902126e-06, '0010110101': 1.5440549138418965e-06, '0010101001': 1.5440549138418965e-06, '0010100101': 1.5440549138418965e-06, '0010101101': 1.5440549138418965e-06, '0110110101': 1.544054913841822e-06, '0110101001': 1.544054913841822e-06}\n"
     ]
    }
   ],
   "source": [
    "# We use direct QAOA to compute approximate max cuts for two subgraphs\n",
    "# In the next section, we will compute these using DC-QAOA because subgraphs might also exceed the qubit limit\n",
    "import paddle\n",
    "from paddle_quantum.QAOA.maxcut import find_cut\n",
    "\n",
    "# Set QAOA parameters\n",
    "p = 3 # Number of layers of QAOA circuit\n",
    "ITR = 100 # Iterations of the training network of QAOA\n",
    "LR = 0.5 # Learning rate in the training network of QAOA\n",
    "# Set graph reconstruction parameter\n",
    "t = 10 # Number of partition strings kept after graph reconstruction \n",
    "paddle.seed(999)  # Fix the seed\n",
    "\n",
    "# Start graph reconstruction procedure\n",
    "S_str_cnt = []\n",
    "for si in S:\n",
    "    siv = list(si.nodes)\n",
    "    # Compute the subgraph's maxcut\n",
    "    tmp, si_str_cnt_relabeled = find_cut(si, p, ITR, LR)\n",
    "    # Make the subgraph's maxcut match the original graph by relabeling \n",
    "    si_str_cnt = []\n",
    "    for str_relabeled in si_str_cnt_relabeled:\n",
    "        strr = \"\"\n",
    "        for i in range(len(G.nodes)):\n",
    "            if i in siv:\n",
    "                strr += str_relabeled[siv.index(i)]\n",
    "            else:\n",
    "                strr += \"x\"\n",
    "        si_str_cnt.append((strr, si_str_cnt_relabeled[str_relabeled]))\n",
    "    si_str_cnt.sort(key=lambda tup:tup[1])\n",
    "    S_str_cnt.append(si_str_cnt[::-1][:t])\n",
    "\n",
    "# Once we have already obatined max cut strings for two paritions, we perform the graph reconstruction (GR)\n",
    "print(\"Max cut for the first partitioned subgraph: \\n\" + str(dict(S_str_cnt[0])))\n",
    "print(\"Max cut for the second partitioned subgraph: \\n\" + str(dict(S_str_cnt[1])))\n",
    "out_cnt = GR(S_str_cnt[0], S_str_cnt[1])\n",
    "print(\"Combined max cut for the original graph: \\n\" + str(dict(out_cnt[:t])))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The top several possible max cuts for the first subgraph include {'010xxxxxxx','101xxxxxxx'} and those for the second subgraph include {'1x10101010','0x01010101'}, where 'x' indicates those missing nodes in the subgraph. Shared nodes $0$ and $2$ are all '0's in the first possibility of the first subgraph, i.e. '010xxxxxxx', while they are all '1's in the first possibility of the second subgraph, i.e. '1x10101010', so they cannot combine. (Note that although we can flip 0s and 1s in this situation by symmetry, it is not necessary). We then try to combine '010xxxxxxx' (first possibility of the first subgraph) and '0x01010101' (second possibility of the second subgraph). It is clear that the shared nodes $0$ and $2$ are all '0's in both subgraphs as shown below in the left and middle figure, so we combine these two max cuts and get '0101010101' for the original cycle of six as shown below in the right.\n",
    "\n",
    "Graph illustration is shown below. The left and middle subgraphs are subgraphs with approximate max cuts, where red and blue nodes represent $S_0$ and $S_1$ and dashed lines represent cuts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:52:49.021611Z",
     "start_time": "2021-05-11T06:52:48.704511Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1080x288 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Computed max cut for two subgraphs\n",
    "strr1 =  '010xxxxxxx'\n",
    "strr2 = '0x01010101' \n",
    "strr = '0101010101'\n",
    "\n",
    "# Show graph illustration\n",
    "options0 = {\n",
    "    \"node_color\": [\"red\" if strr1[i] == '0' else \"blue\" for i in S[0].nodes],\n",
    "    \"style\": [\"solid\" if strr1[u] == strr1[v] else \"dashed\" for (u, v) in list(S[0].edges)]\n",
    "}\n",
    "options1 = {\n",
    "    \"node_color\": [\"red\" if strr2[i] == '0' else \"blue\" for i in S[1].nodes],\n",
    "    \"style\": [\"solid\" if strr2[u] == strr2[v] else \"dashed\" for (u, v) in list(S[1].edges)]\n",
    "}\n",
    "options2 = {\n",
    "    \"node_color\": [\"red\" if strr[i] == '0' else \"blue\" for i in range(n)],\n",
    "    \"style\": [\"solid\" if strr[u] == strr[v] else \"dashed\" for (u, v) in list(G.edges)]\n",
    "}\n",
    "\n",
    "fig, ax = plt.subplots(1, 3, figsize=(15,4))\n",
    "for i, a in enumerate(ax):\n",
    "    a.axis('off')\n",
    "    a.margins(0.20)\n",
    "nx.draw_networkx(S[0], pos=nx.circular_layout(S[0]), ax=ax[0], **options, **options0)\n",
    "nx.draw_networkx(S[1], pos=nx.circular_layout(S[1]), ax=ax[1], **options, **options1)\n",
    "nx.draw_networkx(G, pos=nx.circular_layout(G), ax=ax[2], **options, **options2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### DC-QAOA\n",
    "\n",
    "To find the max cut for a large graph with the number of vertices exceeding limits, DC-QAOA recursively divides it through LGP policy and conquers sub-solutions with GR policy described above. It adopts the divide-and-conquer paradigm to deal with the max-cut problem for large-scale graphs. \n",
    "\n",
    "The input graph is separated into exactly two subgraphs through LGP policy if the vertex size is larger than the qubit limit. Otherwise, its max cut would be directly calculated by QAOA. Each subgraph will recursively call DC-QAOA until its max-cut solution are returned, i.e. at some step, the vertex size of the subgraph is under the limit and can be directly processed by QAOA and returned values would be combined and then be given to the upper layer. \n",
    "\n",
    "The code below provides the way to run DC-QAOA and LGP and GR policies are both applied in the `DC_QAOA` function. Note that QAOA would return a series of possible cuts, sorted by frequency count.   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:54:04.788730Z",
     "start_time": "2021-05-11T06:52:49.025846Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First t possible approximate maxcut for graph G: {'1010101010': 938, '0101010101': 878, '0110101001': 160, '0110101011': 160, '1001010110': 152, '1001010100': 152, '1001010010': 145, '1101010010': 137, '1101010110': 137, '1101010100': 137}\n",
      "Max cut found by DC-QAOA algorithms: 1010101010\n"
     ]
    }
   ],
   "source": [
    "def DC_QAOA(g, p, t, s, k, ITR, LR):\n",
    "    if len(g.nodes) > k:\n",
    "        # get exactly two subgraphs with LGP policy\n",
    "        S = NaiveLGP(g, k)\n",
    "\n",
    "        S_str_cnt = []\n",
    "        for si in S:\n",
    "            siv = list(si.nodes)\n",
    "            # Compute the subgraph's maxcut recursively\n",
    "            _, si_str_cnt_relabeled = DC_QAOA(si, p, t, s, k, ITR, LR)\n",
    "            # refilling str_cnt1 and str_cnt2\n",
    "            si_str_cnt = []\n",
    "            for str_relabeled in si_str_cnt_relabeled:\n",
    "                strr = \"\"\n",
    "                for v in g.nodes:\n",
    "                    if v in siv:\n",
    "                        strr += str_relabeled[siv.index(v)]\n",
    "                    else:\n",
    "                        strr += \"x\"\n",
    "                si_str_cnt.append((strr, si_str_cnt_relabeled[str_relabeled]))\n",
    "            si_str_cnt.sort(key = lambda tup:tup[1])\n",
    "            S_str_cnt.append(si_str_cnt[::-1][:t])\n",
    "        # Reconstruct string-count map with GR policy\n",
    "        out_cnt = GR(S_str_cnt[0], S_str_cnt[1])\n",
    "    else:\n",
    "        if len(g.nodes) == 1:\n",
    "            return [(\"0\", 99999), (\"1\", 99999)]\n",
    "        _, out_cnt = find_cut(g, p, ITR, LR, shots=3000)\n",
    "        # Transform {str:cnt} dictionary into [(st, cnt)] tuple list\n",
    "        out_cnt = [(k, v) for k, v in out_cnt.items()]\n",
    "        # Sort string-count map by counts in reverse order\n",
    "        out_cnt.sort(key=lambda tup:tup[1])\n",
    "        out_cnt = out_cnt[::-1]\n",
    "\n",
    "    # retain only top t (str,cnt) pairs by sorted order\n",
    "    out_cnt = out_cnt[:t]\n",
    "    # resacle total numer of counts to s or around\n",
    "    cnt_sum = sum(cnt for (str, cnt) in out_cnt)\n",
    "    out_cnt = [(k, int(s * v / cnt_sum)) for (k, v) in out_cnt]\n",
    "\n",
    "    return out_cnt[0][0], dict(out_cnt)\n",
    "    \n",
    "# Set QAOA parameters\n",
    "p = 2     # Number of layers of QAOA circuit\n",
    "ITR = 100 # Iterations of the training network of QAOA\n",
    "LR = 0.5  # Learning rate in the training network of QAOA\n",
    "\n",
    "#Set DC-QAOA parameters\n",
    "s = 3000  # Multiplier to make frequency bigger\n",
    "t = 10    # Number of partition strings kept after graph reconstruction \n",
    "k = 5     # Maximum qubits/vertices limit\n",
    "\n",
    "# Using DC-QAOA\n",
    "max_cut, out_cnt = DC_QAOA(G, p, t, s, k, ITR, LR)\n",
    "print(\"First t possible approximate maxcut for graph G: \" + str(out_cnt))\n",
    "print(\"Max cut found by DC-QAOA algorithms: \" + str(max_cut))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Applicability"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**DC-QAOA described above can approximate max cut for a graph if and only if its and one family of its recursive children's pseudo-connectivities are all smaller than $k$, where $k$ is the qubit limit (vertex limit).**\n",
    "\n",
    "The pseudo-connectivity here is defined as the minimum number of vertices that need to be removed to separate the remaining vertices into exactly two isolated subgraphs. A graph's recursive children mean its two partitioned subgraphs and then their partitioned sub-subgraphs until some are smaller or equal to the qubit limit. \n",
    "\n",
    "Cycles are applicable examples if the qubit limit is larger than $1$. Its pseudo-connectivity is $2$ as removing two vertices can partition cycles into two paths. For the example of $C_6$ (cycle of six) with qubit limit 4, partitions described above are $P_5$ (path of five) and $P_2$. $P_2$ is under the qubit limit, and $P_5$ can be partitioned into $P'_4$ and $P'_2$ and thus have pseudo-connectivity $1$. Then $P'_4$ and $P'_2$ are under the qubit limit. So this family of the $C_6$ has all its recursive children's ($C_6$, $P_5$) pseudo-connectivities smaller than $4$. \n",
    "\n",
    "Non applicable examples include complete graphs with $n$ larger than $k$, because no matter how you remove vertices, the rest graph is still connected.  Another example for which different qubit limits influence its applicability is shown below. \n",
    "\n",
    "The left graph is the original graph. If the qubit limit is $2$, then the number of separation nodes can only be $1$ and no vertice could partition the graph into $2$. If we remove vertex $4$ (as shown in the middle), the graph will be partitioned into three while others will leave a connected graph. Besides, the graph's pseudo-connectivity is $2$, not smaller than $k=2$, and so DC-QAOA fails in this case. However, if the qubit limit is $3$, then its pseudo-connectivity is under $k$ and we can remove vertex $0$ and $3$ as shown in the right. Then the rest  are two components, with one under the qubit limit and one can be partitioned into two further (by removing vertex $4$ and with pseudo-connectivity being $1 < k$). So DC-QAOA succeeds here. \n",
    "\n",
    "![limitations-connectivity](./figures/dcqaoa-fig-applicability_example.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "People can try the example shown above by adjusting the parameter $k$ in the code below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:54:45.016920Z",
     "start_time": "2021-05-11T06:54:04.825816Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First t possible approximate maxcut for graph G: {'00001': 532, '00101': 501, '11110': 496, '01001': 496, '10110': 492, '11010': 483}\n"
     ]
    }
   ],
   "source": [
    "G = nx.Graph()\n",
    "G.add_nodes_from([0, 1, 2, 3, 4])\n",
    "G.add_edges_from([(0, 4), (1, 2), (1, 4), (2, 4), (3, 4)])\n",
    "k = 3\n",
    "_, out_cnt = DC_QAOA(G, p, t, s, k, ITR, LR)\n",
    "print(\"First t possible approximate maxcut for graph G: \" + str(dict(out_cnt)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Performance\n",
    "\n",
    "We have compared DC-QAOA with classical max-cut approximation algorithms to test its performance. We provide the performance below of finding max-cut by DC-QAOA and the upper bound for max cut provided by SDP. We take five random graphs of 10 vertices as an example to show the performance (qubit limit for DC-QAOA is set to be 5). \n",
    "\n",
    "In order to run the following test, users need to install cvxpy: `pip install cvxpy`. **Windows users may encounter an error at runtime if they install cvxpy using pip. Instead, we recommend Windows users to create a new conda environment and install cvxpy with conda.** For more details please see [https://www.cvxpy.org/install/](https://www.cvxpy.org/install/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T06:54:47.679276Z",
     "start_time": "2021-05-11T06:54:47.341106Z"
    }
   },
   "outputs": [],
   "source": [
    "import cvxpy as cvx\n",
    "import networkx as nx\n",
    "\n",
    "def sdp_solver(G):\n",
    "    \"\"\"\n",
    "    Use SDP to find the upper bound for the max-cut problem.\n",
    "    \"\"\"\n",
    "    n = len(G)\n",
    "    adj_mat = nx.adjacency_matrix(G).toarray()\n",
    "    Y = cvx.Variable((n, n), PSD=True)\n",
    "    cut_size = 0.25 * cvx.sum(cvx.multiply(adj_mat, 1 - Y))\n",
    "    problem = cvx.Problem(cvx.Maximize(cut_size), [cvx.diag(Y) == 1])\n",
    "    opt_val = problem.solve(cvx.SCS)\n",
    "\n",
    "    return opt_val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T07:02:35.277145Z",
     "start_time": "2021-05-11T06:54:47.682769Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of node = 10\n",
      "Node = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
      "\n",
      "Random graph 1\n",
      "Edges = [(0, 2), (0, 6), (0, 7), (0, 8), (1, 3), (1, 5), (1, 6), (1, 8), (1, 9), (2, 3), (2, 4), (2, 6), (2, 8), (2, 9), (3, 4), (3, 6), (3, 7), (3, 8), (3, 9), (4, 9), (5, 8), (7, 9), (8, 9)]\n",
      "SDP upper bound: 17.750789460578076\n",
      "DC-QAOA node partition: 1001011001, max cut = 17.0\n",
      "\n",
      "Random graph 2\n",
      "Edges = [(0, 1), (0, 3), (0, 6), (1, 2), (1, 3), (2, 5), (2, 6), (2, 7), (3, 5), (3, 6), (3, 8), (3, 9), (4, 6), (4, 7), (4, 8), (4, 9), (5, 7), (5, 8), (6, 7), (6, 8), (7, 9)]\n",
      "SDP upper bound: 16.64755118085844\n",
      "DC-QAOA node partition: 1100111001, max cut = 15.0\n",
      "\n",
      "Random graph 3\n",
      "Edges = [(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 3), (2, 4), (2, 6), (2, 7), (2, 8), (4, 5), (4, 7), (4, 9), (5, 7), (5, 8), (5, 9), (6, 7), (7, 8), (8, 9)]\n",
      "SDP upper bound: 19.402766322145684\n",
      "DC-QAOA node partition: 1101100010, max cut = 18.0\n",
      "\n",
      "Random graph 4\n",
      "Edges = [(0, 1), (0, 2), (0, 5), (0, 6), (0, 7), (0, 9), (1, 5), (1, 6), (1, 7), (1, 9), (2, 3), (2, 6), (2, 8), (3, 5), (3, 6), (3, 8), (3, 9), (4, 5), (4, 6), (4, 7), (4, 9), (5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (7, 8)]\n",
      "SDP upper bound: 20.999869854784496\n",
      "DC-QAOA node partition: 0010011011, max cut = 18.0\n",
      "\n",
      "Random graph 5\n",
      "Edges = [(0, 1), (0, 4), (0, 7), (1, 2), (1, 3), (1, 6), (1, 7), (1, 8), (1, 9), (2, 4), (2, 7), (2, 9), (3, 7), (3, 9), (4, 5), (4, 6), (4, 8), (5, 6), (5, 7), (5, 8), (6, 7), (6, 8), (6, 9), (7, 9), (8, 9)]\n",
      "SDP upper bound: 19.454398132157152\n",
      "DC-QAOA node partition: 1011011001, max cut = 18.0\n"
     ]
    }
   ],
   "source": [
    "n = 10\n",
    "iter = 5\n",
    "print(\"Number of node = \" + str(n))\n",
    "print(\"Node = \" + str([i for i in range(n)]))\n",
    "\n",
    "value_dc_qaoa_ls = []\n",
    "ubound_sdp_ls = []\n",
    "for i in range(iter):\n",
    "        print(\"\\nRandom graph \" + str(i+1))\n",
    "        # Generate random graph\n",
    "        G = nx.erdos_renyi_graph(n, 0.1, 100 * i, directed=False)\n",
    "        while nx.is_connected(G) == False:\n",
    "            G = nx.erdos_renyi_graph(n, 0.5, directed=False)\n",
    "        print(\"Edges = \" + str(list(G.edges)))\n",
    "        # SDP upper bound calculation \n",
    "        ubound_sdp = sdp_solver(G)\n",
    "        ubound_sdp_ls.append(ubound_sdp)\n",
    "        print(\"SDP upper bound: \" + str(ubound_sdp))\n",
    "\n",
    "        # QAOA parameters\n",
    "        p = 2     # Number of layers of QAOA circuit\n",
    "        ITR = 100 # Iterations of the training network of QAOA\n",
    "        LR = 0.5  # Learning rate in the training network of QAOA\n",
    "        # DC-QAOA parameters\n",
    "        s = 3000  # Multiplier to make frequency bigger\n",
    "        t = 20    # Number of partition strings kept after graph reconstruction \n",
    "        k = 5     # Maximum qubits/vertices limit\n",
    "\n",
    "        try:\n",
    "            cut_dc_qaoa, out_cnt = DC_QAOA(G, p, t, s, k, ITR, LR)\n",
    "            cut_dc_qaoa1 = [\"solid\" if cut_dc_qaoa[u] == cut_dc_qaoa[v] else \"dashed\" for (u, v) in list(G.edges)]\n",
    "            value_dc_qaoa = cut_dc_qaoa1.count(\"dashed\")\n",
    "            value_dc_qaoa_ls.append(value_dc_qaoa)\n",
    "            print(\"DC-QAOA node partition: \" + str(cut_dc_qaoa) + \", max cut = \" + str(float(value_dc_qaoa))) \n",
    "        except Exception as e:\n",
    "            value_dc_qaoa = 0\n",
    "            value_dc_qaoa_ls.append(value_dc_qaoa)\n",
    "            print(\"DC-QAOA fails with error message '\" + str(e) + \"'\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T07:02:35.547590Z",
     "start_time": "2021-05-11T07:02:35.280626Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.plot(value_dc_qaoa_ls, label=\"DC-QAOA\")\n",
    "plt.plot(ubound_sdp_ls, label=\"SDP upper bound\", linestyle=\"--\")\n",
    "plt.title('Max-Cut Performancce')\n",
    "plt.xlabel('Random Graph')\n",
    "plt.ylabel('Calculated Optimal Max Cut')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From the line graph above, we have verified that max-cut generated by DC-QAOA is under and close to this bound.\n",
    "\n",
    "## Applications\n",
    "\n",
    "The Max-Cut problem belongs to quadratic unconstrained binary optimization (QUBO), which has a wide range of applications, from finding ground states for the spin glass problem to modeling NP-hard problems [5]. The Max-Cut problem itself inherits widespread usefulness.\n",
    "\n",
    "It is extensively related to various fields, including VLSI circuit design, statistical physics. Both the problem of minimizing the number of vias subject to pin preassignments and layer preferences and the problem of finding ground states of spin glasses with exterior magnetic field in the Ising model can be reduced to the Max-Cut problem [6]. \n",
    "\n",
    "Also importantly, the Max-Cut problem provides a prototypical testbed for algorithmic techniques that can be applied to many interesting problems. For example, SDP relaxation of the Max-Cut problem is adopted in designing data clustering algorithms [7] and addressing the phase retrieval problem [8, 9].\n",
    "\n",
    "More detailed investigations on the Max-Cut problem can be found in [10-12]."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## References\n",
    "\n",
    "[1] Akshay, V., et al. \"Reachability deficits in quantum approximate optimization.\" [Physical Review Letters 124.9 (2020): 090504.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.124.090504)\n",
    "\n",
    "[2] Li, Junde, Mahabubul Alam, and Swaroop Ghosh. \"Large-scale Quantum Approximate Optimization via Divide-and-Conquer.\" [arXiv preprint arXiv:2102.13288 (2021).](https://arxiv.org/abs/2101.03717)\n",
    "\n",
    "[3] Goemans, Michel X., and David P. Williamson. \"Improved approximation algorithms for maximum cut and satisfiability problems using semidefinite programming.\" [Journal of the ACM (JACM) 42.6 (1995): 1115-1145.](http://www-math.mit.edu/~goemans/PAPERS/maxcut-jacm.pdf)\n",
    "\n",
    "[4] Burer, Samuel, and Renato DC Monteiro. \"Local minima and convergence in low-rank semidefinite programming.\" [Mathematical Programming 103.3 (2005): 427-444.](https://link.springer.com/article/10.1007/s10107-004-0564-1)\n",
    "\n",
    "[5] Kochenberger, Gary, et al. \"The unconstrained binary quadratic programming problem: a survey.\" [Journal of Combinatorial Optimization 28.1 (2014): 58-81.](https://link.springer.com/article/10.1007/s10878-014-9734-0)\n",
    "\n",
    "[6] Barahona, Francisco, et al. \"An application of combinatorial optimization to statistical physics and circuit layout design.\" [Operations Research 36.3 (1988): 493-513.](https://www.jstor.org/stable/170992?seq=1)\n",
    "\n",
    "[7] Poland, Jan, and Thomas Zeugmann. \"Clustering pairwise distances with missing data: Maximum cuts versus normalized cuts.\" [International Conference on Discovery Science. Springer, Berlin, Heidelberg, 2006.](https://link.springer.com/chapter/10.1007/11893318_21)\n",
    "\n",
    "[8] Candes, Emmanuel J., et al. \"Phase retrieval via matrix completion.\" [SIAM review 57.2 (2015): 225-251.](https://epubs.siam.org/doi/10.1137/110848074)\n",
    "\n",
    "[9] Waldspurger, Irene, Alexandre d’Aspremont, and Stéphane Mallat. \"Phase recovery, maxcut and complex semidefinite programming.\" [Mathematical Programming 149.1 (2015): 47-81.](https://link.springer.com/article/10.1007/s10107-013-0738-9)\n",
    "\n",
    "[10] Deza, Michel, and Monique Laurent. \"Applications of cut polyhedra—I.\" [Journal of Computational and Applied Mathematics 55.2 (1994): 191-216.](https://www.sciencedirect.com/science/article/pii/0377042794900205)\n",
    "\n",
    "[11] Deza, Michel, and Monique Laurent. \"Applications of cut polyhedra—II.\" [Journal of Computational and Applied Mathematics 55.2 (1994): 217-247.](https://www.sciencedirect.com/science/article/pii/0377042794900213)\n",
    "\n",
    "[12] Poljak, Svatopluk, and Zsolt Tuza. \"Maximum cuts and largest bipartite subgraphs.\" [DIMACS Series 20 (1995): 181-244.](https://arxiv.org/pdf/1810.12144.pdf)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
